using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[AddComponentMenu("House Builder/Pixel Room Builder")]
public class PixelRoomBuilder : MonoBehaviour
{
    [SerializeField]
    private Transform wallBlockPrefab;
    [SerializeField]
    private Transform floorBlockPrefab;

    //private Transform[] walls = new Transform[4];
    private List<List<Transform>> floorBlocks = new List<List<Transform>>();
    private List<List<Transform>> forwardWallBlocks = new List<List<Transform>>();
    private List<List<Transform>> backWallBlocks = new List<List<Transform>>();
    private List<List<Transform>> rightWallBlocks = new List<List<Transform>>();
    private List<List<Transform>> leftWallBlocks = new List<List<Transform>>();
    private Transform floorBlockTrans;
    private Transform forwardWallBlockTrans;
    private Transform backWallBlockTrans;
    private Transform rightWallBlockTrans;
    private Transform leftWallBlockTrans;

    private int floorLength = 5;
    public int FloorLength { get => floorLength; set => floorLength = value; }
    private int floorWeight = 5;
    public int FloorWeight { get => floorWeight; set => floorWeight = value; }
    private int wallHeight = 5;
    public int WallHeight { get => wallHeight; set => wallHeight = value; }
    private int currFloorLength;
    public int CurrFloorLength { get => currFloorLength; set => currFloorLength = value; }
    private int currFloorWeight;
    public int CurrFloorWeight { get => currFloorWeight; set => currFloorWeight = value; }
    private int currWallHeight;
    public int CurrWallHeight { get => currWallHeight; set => currWallHeight = value; }

    private bool isBuilded = false;

    public void BuildARoom()
    {
        if (!isBuilded)
        {
            // Create father Object.
            if (floorBlockTrans == null)
            {
                floorBlockTrans = new GameObject("Floor Blocks").transform;
                floorBlockTrans.SetParent(this.transform);
            }
            if (forwardWallBlockTrans == null)
            {
                forwardWallBlockTrans = new GameObject("Forward Wall").transform;
                forwardWallBlockTrans.SetParent(this.transform);
            }
            if (backWallBlockTrans == null)
            {
                backWallBlockTrans = new GameObject("Back Wall").transform;
                backWallBlockTrans.SetParent(this.transform);
            }
            if (rightWallBlockTrans == null)
            {
                rightWallBlockTrans = new GameObject("Right Wall").transform;
                rightWallBlockTrans.SetParent(this.transform);
            }
            if (leftWallBlockTrans == null)
            {
                leftWallBlockTrans = new GameObject("Left Wall").transform;
                leftWallBlockTrans.SetParent(this.transform);
            }

            // Create FloorBlocks.     
            if (floorBlocks.Count == 0)
            {
                for (int i = 0; i < floorLength; i++)
                {
                    List<Transform> blocks = new List<Transform>();
                    for (int j = 0; j < floorWeight; j++)
                    {

                        blocks.Add(CreateABlock(
                            floorBlockPrefab,
                            new Vector3((float)j + 0.5f, 0f, (float)i + 0.5f),
                            new Vector3(90f, 0f, 0f),
                            floorBlockTrans
                            ));
                    }
                    floorBlocks.Add(blocks);
                }
            }

            // Create Walls.
            // Left wall
            if (leftWallBlocks.Count == 0)
            {
                for (int i = 0; i < floorLength; i++)
                {
                    List<Transform> blocks = new List<Transform>();
                    for (int j = 0; j < wallHeight; j++)
                    {
                        blocks.Add(CreateABlock(
                            wallBlockPrefab,
                            new Vector3(0f, 0.5f + (float)j, 0.5f + (float)i),
                            new Vector3(0f, -90f, 0f),
                            leftWallBlockTrans
                            ));
                    }
                    leftWallBlocks.Add(blocks);
                }
            }

            // Back wall
            if (backWallBlocks.Count == 0)
            {
                for (int i = 0; i < floorWeight; i++)
                {
                    List<Transform> blocks = new List<Transform>();
                    for (int j = 0; j < wallHeight; j++)
                    {
                        blocks.Add(CreateABlock(
                            wallBlockPrefab,
                            new Vector3(0.5f + (float)i, 0.5f + (float)j, 0f),
                            new Vector3(0f, 180f, 0f),
                            backWallBlockTrans
                            ));
                    }
                    backWallBlocks.Add(blocks);
                }
            }

            // Forward wall
            if (forwardWallBlocks.Count == 0)
            {
                for (int i = 0; i < floorWeight; i++)
                {
                    List<Transform> blocks = new List<Transform>();
                    for (int j = 0; j < wallHeight; j++)
                    {
                        blocks.Add(CreateABlock(
                            wallBlockPrefab,
                            new Vector3(0.5f + (float)i, 0.5f + (float)j, floorLength),
                            new Vector3(0f, 0f, 0f),
                            forwardWallBlockTrans
                            ));
                    }
                    forwardWallBlocks.Add(blocks);
                }
            }

            // Right wall
            if (rightWallBlocks.Count == 0)
            {
                for (int i = 0; i < floorLength; i++)
                {
                    List<Transform> blocks = new List<Transform>();
                    for (int j = 0; j < wallHeight; j++)
                    {
                        blocks.Add(CreateABlock(
                            wallBlockPrefab,
                            new Vector3(floorWeight, 0.5f + (float)j, 0.5f + (float)i),
                            new Vector3(0f, 90f, 0f),
                            rightWallBlockTrans
                            ));
                    }
                    rightWallBlocks.Add(blocks);
                }
            }

            currFloorLength = floorLength;
            currFloorWeight = floorWeight;
            currWallHeight = wallHeight;

            isBuilded = true;
        }     
    }

    int addCountNum;

    public void ChangeRoomSize()
    {
        if(isBuilded)
        {
            // Wall Height           
            ChangeWallHeight();

            // Floor Length
            ChangeFloorLength();

            // Floor Weight
            ChangeFloorWeight();

            currFloorLength = floorLength;
            currFloorWeight = floorWeight;
            currWallHeight = wallHeight;
        }
    }

    private void ChangeWallHeight()
    {
        // ++         
        if (wallHeight > currWallHeight)
        {
            addCountNum = wallHeight - currWallHeight;

            for (int index = 0; index < addCountNum; index++)
            {
                // Forward
                for (int i = 0; i < floorWeight; i++)
                {
                    forwardWallBlocks[i].Add(CreateABlock(
                            wallBlockPrefab,
                            new Vector3(i + 0.5f, currWallHeight - 0.5f + index + 1f, currFloorLength),
                            new Vector3(0f, 0f, 0f),
                            forwardWallBlockTrans
                            ));
                }

                // Back
                for (int i = 0; i < floorWeight; i++)
                {
                    backWallBlocks[i].Add(CreateABlock(
                            wallBlockPrefab,
                            new Vector3(i + 0.5f, currWallHeight - 0.5f + index + 1f, 0f),
                            new Vector3(0f, 180f, 0f),
                            backWallBlockTrans
                            ));
                }

                // Left
                for (int i = 0; i < floorLength; i++)
                {
                    leftWallBlocks[i].Add(CreateABlock(
                            wallBlockPrefab,
                            new Vector3(0f, currWallHeight - 0.5f + index + 1f, i + 0.5f),
                            new Vector3(0f, -90f, 0f),
                            leftWallBlockTrans
                            ));
                }

                // Right
                for (int i = 0; i < floorLength; i++)
                {
                    rightWallBlocks[i].Add(CreateABlock(
                            wallBlockPrefab,
                            new Vector3(currFloorWeight, currWallHeight - 0.5f + index + 1f, i                                        + 0.5f),
                            new Vector3(0f, 90f, 0f),
                            rightWallBlockTrans
                            ));
                }
            }             
        }
        // --
        else if (wallHeight < currWallHeight)
        {
            addCountNum = currWallHeight - wallHeight;

            for (int index = 0; index < addCountNum; index++)
            {
                // Forward
                for (int i = 0; i < floorWeight; i++)
                {
                    DestroyABlock(forwardWallBlocks[i][currWallHeight - 1].gameObject);
                    forwardWallBlocks[i].RemoveAt(currWallHeight - 1);
                }

                // Back
                for (int i = 0; i < floorWeight; i++)
                {
                    DestroyABlock(backWallBlocks[i][currWallHeight - 1].gameObject);
                    backWallBlocks[i].RemoveAt(currWallHeight - 1);
                }

                // Left
                for (int i = 0; i < floorLength; i++)
                {
                    DestroyABlock(leftWallBlocks[i][currWallHeight - 1].gameObject);
                    leftWallBlocks[i].RemoveAt(currWallHeight - 1);
                }

                // Right
                for (int i = 0; i < floorLength; i++)
                {
                    DestroyABlock(rightWallBlocks[i][currWallHeight - 1].gameObject);
                    rightWallBlocks[i].RemoveAt(currWallHeight - 1);
                }
            }   
        }
    }

    private void ChangeFloorLength()
    {
        // ++  
        if (floorLength > currFloorLength)
        {
            addCountNum = floorLength - currFloorLength;
                  
            for(int index = 0; index < addCountNum; index++)
            {
                // Floor   
                List<Transform> floorBlockList = new List<Transform>();
                for (int j = 0; j < floorWeight; j++)
                {
                    floorBlockList.Add(CreateABlock(
                            floorBlockPrefab,
                            new Vector3((float)j + 0.5f, 0f, currFloorLength - 0.5f + index + 1f),
                            new Vector3(90f, 0f, 0f),
                            floorBlockTrans
                            ));
                }
                floorBlocks.Add(floorBlockList);

                // Left wall
                List<Transform> leftWallBlockList = new List<Transform>();
                for (int j = 0; j < wallHeight; j++)
                {
                    leftWallBlockList.Add(CreateABlock(
                            wallBlockPrefab,
                            new Vector3(0f, currWallHeight - 0.5f - j, currFloorLength - 0.5f + index + 1f),
                            new Vector3(0f, -90f, 0f),
                            leftWallBlockTrans
                            ));
                }
                leftWallBlocks.Add(leftWallBlockList);

                // Right wall
                List<Transform> rightWallBlockList = new List<Transform>();
                for (int j = 0; j < wallHeight; j++)
                {
                    rightWallBlockList.Add(CreateABlock(
                            wallBlockPrefab,
                            new Vector3(currFloorWeight, currWallHeight - 0.5f - j, currFloorLength - 0.5f + index + 1),
                            new Vector3(0f, 90f, 0f),
                            rightWallBlockTrans
                            ));
                }
                rightWallBlocks.Add(rightWallBlockList);

                // Forward wall Pos
                for (int i = 0; i < forwardWallBlocks.Count; i++)
                {
                    for (int j = 0; j < forwardWallBlocks[i].Count; j++)
                    {
                         forwardWallBlocks[i][j].localPosition = new Vector3(
                            forwardWallBlocks[i][j].localPosition.x,
                            forwardWallBlocks[i][j].localPosition.y,
                            forwardWallBlocks[i][j].localPosition.z + 1);
                    }
                }
            }            
        }
        // --
        else if (floorLength < currFloorLength)
        {
            if(floorBlocks.Count != 0)
            {
                addCountNum = currFloorLength - floorLength;

                for (int index = 0; index < addCountNum; index++)
                {
                    // Floor
                    for (int j = 0; j < floorWeight; j++)
                    {
                        DestroyABlock(floorBlocks[currFloorLength - 1 - index][j].gameObject);
                    }
                    floorBlocks.RemoveAt(currFloorLength - 1 - index);

                    // Left wall
                    for (int j = 0; j < wallHeight; j++)
                    {
                        DestroyABlock(leftWallBlocks[currFloorLength - 1 - index][j].gameObject);
                    }
                    leftWallBlocks.RemoveAt(currFloorLength - 1 - index);

                    // Right wall
                    for (int j = 0; j < wallHeight; j++)
                    {
                        DestroyABlock(rightWallBlocks[currFloorLength - 1 - index][j].gameObject);
                    }
                    rightWallBlocks.RemoveAt(currFloorLength - 1 - index);

                    // Forward wall Pos
                    for (int i = 0; i < forwardWallBlocks.Count; i++)
                    {
                        for (int j = 0; j < forwardWallBlocks[i].Count; j++)
                        {
                            forwardWallBlocks[i][j].localPosition = new Vector3(
                                forwardWallBlocks[i][j].localPosition.x,
                                forwardWallBlocks[i][j].localPosition.y,
                                forwardWallBlocks[i][j].localPosition.z - 1);
                        }
                    }
                }
            }                        
        }
    }

    private void ChangeFloorWeight()
    {
        // ++
        if (floorWeight > currFloorWeight)
        {
            addCountNum = floorWeight - currFloorWeight;

            for (int index = 0; index < addCountNum; index++)
            {
                // Floor
                for (int i = 0; i < floorLength; i++)
                {
                    floorBlocks[i].Add(CreateABlock(
                        floorBlockPrefab,
                        new Vector3(currFloorWeight - 0.5f + index + 1f, 0f, (float)i + 0.5f),
                        new Vector3(90f, 0f, 0f),
                        floorBlockTrans
                        ));
                }

                // Forward wall
                List<Transform> forwardWallBlockList = new List<Transform>();
                for (int i = 0; i < wallHeight; i++)
                {
                    forwardWallBlockList.Add(CreateABlock(
                            wallBlockPrefab,
                            new Vector3(currFloorWeight - 0.5f + index + 1f, currWallHeight - 0.5f - i, currFloorLength),
                            new Vector3(0f, 0f, 0f),
                            forwardWallBlockTrans
                            ));
                }
                forwardWallBlocks.Add(forwardWallBlockList);

                // Back wall
                List<Transform> backWallBlockList = new List<Transform>();
                for (int i = 0; i < wallHeight; i++)
                {
                    backWallBlockList.Add(CreateABlock(
                            wallBlockPrefab,
                            new Vector3(currFloorWeight - 0.5f + index + 1f, currWallHeight - 0.5f - i, 0f),
                            new Vector3(0f, 180f, 0f),
                            backWallBlockTrans
                            ));
                }
                backWallBlocks.Add(backWallBlockList);

                // Right wall Pos
                for (int i = 0; i < rightWallBlocks.Count; i++)
                {
                    for (int j = 0; j < rightWallBlocks[i].Count; j++)
                    {
                        rightWallBlocks[i][j].localPosition = new Vector3(
                           rightWallBlocks[i][j].localPosition.x + 1,
                           rightWallBlocks[i][j].localPosition.y,
                           rightWallBlocks[i][j].localPosition.z);
                    }
                }
            }
        }
        // --
        else if (floorWeight < currFloorWeight)
        {
            if (floorBlocks[0].Count != 0)
            {
                addCountNum = currFloorWeight - floorWeight;

                for (int index = 0; index < addCountNum; index++)
                {
                    // Floor
                    for (int i = 0; i < floorLength; i++)
                    {
                        DestroyABlock(floorBlocks[i][currFloorWeight - 1 - index].gameObject);
                        floorBlocks[i].RemoveAt(currFloorWeight - 1 - index);
                    }


                    // Forward wall
                    for (int i = 0; i < wallHeight; i++)
                    {
                        DestroyABlock(forwardWallBlocks[currFloorWeight - 1 - index][i].gameObject);
                    }
                    forwardWallBlocks.RemoveAt(currFloorWeight - 1 - index);

                    // Back wall
                    for (int i = 0; i < wallHeight; i++)
                    {
                        DestroyABlock(backWallBlocks[currFloorWeight - 1 - index][i].gameObject);
                    }
                    backWallBlocks.RemoveAt(currFloorWeight - 1 - index);

                    // Right wall Pos
                    for (int i = 0; i < rightWallBlocks.Count; i++)
                    {
                        for (int j = 0; j < rightWallBlocks[i].Count; j++)
                        {
                            rightWallBlocks[i][j].localPosition = new Vector3(
                                rightWallBlocks[i][j].localPosition.x - 1,
                                rightWallBlocks[i][j].localPosition.y,
                                rightWallBlocks[i][j].localPosition.z);
                        }
                    }
                }
            }
        }
    }

    public void ClearAllObject()
    {
        if(leftWallBlockTrans != null && rightWallBlockTrans != null && 
            forwardWallBlockTrans != null && backWallBlockTrans != null &&
            floorBlockTrans != null)
        {
            // Clear walls.
            leftWallBlocks.Clear();
            DestroyABlock(leftWallBlockTrans.gameObject);

            rightWallBlocks.Clear();
            DestroyABlock(rightWallBlockTrans.gameObject);

            forwardWallBlocks.Clear();
            DestroyABlock(forwardWallBlockTrans.gameObject);

            backWallBlocks.Clear();
            DestroyABlock(backWallBlockTrans.gameObject);

            // Clear Floorblocks.
            floorBlocks.Clear();
            DestroyABlock(floorBlockTrans.gameObject);

            isBuilded = false;
        }
    }

    private Transform CreateABlock(Transform prefab, Vector3 pos, Vector3 rot, Transform parent)
    {
        Transform block = Instantiate(prefab);
        block.localPosition = pos;
        block.localEulerAngles = rot;
        block.localScale = new Vector3(1f, 1f, 1f);
        block.SetParent(parent);
        return block;
    }

    private void DestroyABlock(GameObject block)
    {
        DestroyImmediate(block, true);
    }
}
